<template>
  <erp-table
    ref="erpTable"
    v-loading="!detailTableDataSource"
    :element-loading-spinner="$store.state.loading.spinner"
    :element-loading-text="$store.state.loading.text"
    :element-loading-background="$store.state.loading.background"
    v-bind="$attrs"
    :height="maxHeight"
    :keep-source="editable ? keepSource : false"
    :edit-config="editConfigCom"
    :keyboard-config="keyboardConfigCom"
    :mouse-config="mouseConfigCom"
    :auto-resize="autoResize"
    :border="border"
    :stripe="false"
    :show-overflow="showOverflow"
    :show-footer="showFooter"
    :footer-method="footerMethodCom"
    footer-row-class-name="erp-table-footer-row"
    :list-permission="true"
    :custom-config="customConfigCom"
    :edit-rules="editRulesCom"
    row-class-name="erp-detail-table__row"
    v-on="$listeners"
    @cell-mouseenter="handleCellMouseenter"
    @cell-mouseleave="handleCellMouseleave"
    @clear="handleClear"
    @cell-click="handleSingleSelect"
  >
    <template slot="default">
      <vxe-table-column
        type="html"
        width="50"
        fixed="left"
        align="center"
        :class-name="editable ? 'readonly' : ''"
      >
        <template #header="{column}">
          #
        </template>
        <template #default="{$rowIndex, row}">
          <div
            v-if="currentEnterRow == $rowIndex"
            class="seq-icons"
          >
            <div
              class="seq-icon"
              @click.stop="insertTable(row)"
            >
              <i class="iconfont icon-add add" />
            </div>
            <div
              class="seq-icon"
              @click.stop="deleteTable(row)"
            >
              <i class="iconfont icon-yichu remove" />
            </div>
          </div>
          <div v-else>
            {{ $rowIndex + 1 }}
          </div>
        </template>
      </vxe-table-column>
      <vxe-table-column
        v-if="editable && draggable"
        title="拖拽排序"
        align="center"
        :class-name="editable ? 'readonly' : ''"
        width="70"
      >
        <template #default>
          <span
            class="drag-btn"
            style="cursor: move"
          >
            <i class="vxe-icon--menu" />
          </span>
        </template>
      </vxe-table-column>
      
      <erp-table-column
        v-for="(column, index) in columnsCom"
        :key="column.field || index"
        v-bind="column"
        :params="paramsCom"
      />
      <vxe-table-column
        v-if="operation"
        title="操作"
        align="center"
        fixed="right"
        :class-name="editable ? 'readonly' : ''"
        width="150"
      >
        <template slot-scope="{row}">
        
          <el-button v-if="manual" type="text" @click="handleManual(row)" :disabled="row.curPkgNum > '0.000' ? true : false">手工录入</el-button>
          <el-button v-if="editDetail" type="text" @click="handleEdit(row)" :disabled="row.curPkgNum > '0.000' ? true : false">编辑</el-button>
        </template>
      </vxe-table-column>
      <!--            <slot name="default" v-if="detailTableDataSource" :source="detailTableDataSource"></slot>-->
    </template>
  </erp-table>
</template>

<script>
import {VXETable} from 'vxe-table';
import VXETablePluginElement from 'vxe-table-plugin-element';
import {base as request} from '@/request';
import ErpTable from './ErpTable';
import {toast, cloneJson} from "../../../utils";
import ErpTableColumn from '@/components/erp/ErpTableColumn';
import Sortable from 'sortablejs';
VXETable.use(VXETablePluginElement);
/**
 * 可编辑表格
 * @author maolin
 */
export default {
  name: "ErpDetailTable",
  components: {
    ErpTable,
    ErpTableColumn,
  },
  beforeRouteLeave (to, from, next) {
    if (this.createNewRecordTimer) {
      clearInterval(this.createNewRecordTimer);
    }
    next();
  },
  props: {
    /**
     * 是否可见
     * @public
     */
    visible: {
      type: Boolean,
      default: true
    },
    /**
     * 是否可拖拽
     * @public
     */
    draggable: {
      type: Boolean,
      default: true
    },
    /**
     * 是否开启手工录入
     * @public
     */
    manual: {
      type: Boolean,
      default: false
    },
    /**
     * 是否开启编辑
     * @public
     */
    editDetail: {
      type: Boolean,
      default: false
    }, 
    /**
     * 是否开启编辑
     * @public
     */
    operation: {
      type: Boolean,
      default: false
    }, 

    /**
     * 是否禁用操作行
     * @public
     */
    disabledOperation: {
      type: Boolean,
      default: false
    },
    /**
     * 拖拽后执行的函数
     * @public
     */
    afterDrag: {
      type: Function,
      default () {}
    },
    /**
     * 表单对象
     * @public
     */
    form: {
      type: Object,
      default: () => {}
    },
    /**
     * 数据源对象
     * @public
     */
    dataSource: {
      type: Object,
      default: () => {}
    },
    /**
     * 接收的表格数据
     * @public
     */
    data: {
      type: Array,
      default: () => []
    },
    /**
     * 排序列的高度
     * @public
     */
    seqHeight: {
      type: [String, Number],
      default: '48px'
    },
    /**
     * 请求的api对象
     * @public
     */
    apiList: {
      type: Object,
      default () {
        return {
          dataSourceApi: {
            url: "",
          }
        };
      }
    },
    /**
     * 高度
     * @public
     */
    height: {
      type: [String, Number],
      default: ''
    },
    /**
     * 最大高度
     * @public
     */
    maxHeight: {
      type: [String, Number],
      default: ''
    },
    /**
     * 保持原始值的状态，被某些功能所依赖，比如编辑状态、还原数据等（开启后影响性能，具体取决于数据量）
     * @public
     */
    keepSource: {
      type: Boolean,
      default: true,
    },
    /**
     * 是否显示表格底部
     * @public
     */
    showFooter: {
      type: Boolean,
      default: true,
    },
    /**
     * 是否可自动计算宽度
     * @public
     */
    autoResize: {
      type: Boolean,
      default: true,
    },
    /**
     * 表尾的数据获取方法，返回一个二维数组
     * @public
     */
    footerMethod: {
      type: Function,
      default () {}
    },
    /**
     * 是否开启边框
     * @public
     */
    border: {
      type: Boolean,
      default: true,
    },
    /**
     * 设置所有内容过长时显示为省略号（如果是固定列建议设置该值，提升渲染速度）
     * @public
     */
    showOverflow: {
      type: Boolean,
      default: true,
    },
    /**
     * 编辑表格配置，参考[vxe-table](https://xuliangzhan_admin.gitee.io/vxe-table/v3/#/table/api)
     * @public
     */
    editConfig: {
      type: Object,
      default () {
        return {};
      }
    },
    /**
     * 按键配置，参考[vxe-table](https://xuliangzhan_admin.gitee.io/vxe-table/v3/#/table/api)
     * @public
     */
    keyboardConfig: {
      type: Object,
      default () {
        return {};
      }
    },
    /**
     * 鼠标配置，参考[vxe-table](https://xuliangzhan_admin.gitee.io/vxe-table/v3/#/table/api)
     * @public
     */
    mouseConfig: {
      type: Object,
      default () {
        return {};
      }
    },
    /**
     * 校验规则配置，参考[vxe-table](https://xuliangzhan_admin.gitee.io/vxe-table/v3/#/table/api)
     * @public
     */
    editRules: {
      type: Object,
      default () {
        return {};
      }
    },
    /**
     * 自定义列配置，参考[vxe-table](https://xuliangzhan_admin.gitee.io/vxe-table/v3/#/table/api)
     * @public
     */
    customConfig: {
      type: Object,
      default () {
        return {};
      }
    },
    /**
     * 是否可编辑
     * @public
     */
    editable: {
      type: Boolean,
      default: true
    },
    /**
     * 是否是新记录，创建或复制
     * @public
     */
    isNewRecord: {
      type: Boolean,
      default: true
    },
    /**
     * 是否是复制
     * @public
     */
    isCopy: {
      type: Boolean,
      default: false
    },
    /**
     * [配置项](../eg/ErpDetailTable.html#config)
     * @public
     */
    config: {
      type: Object,
      default () {
        return {};
      }
    }
  },
  data () {
    return {
      detailTableDataSource: null,
      currentEnterRow: null
    };
  },
  computed: {
    effectRow () {
      return this.config && this.config.effectRow ? this.config.effectRow : [];
    },
    footerMethodCom () {
      if (this.config && this.config.footerMethod && typeof this.config.footerMethod === 'function') {
        return (e) => {
          return this.config.footerMethod(e, {form: this.form, editable: this.editable});
        };
      } else {
        return this.footerMethod;
      }
    },
    editRulesCom () {
      if (!this.editable) {
        return null;
      }
      let defaultConfig = this.editRules;
      if (this.config && this.config.editRules) {
        defaultConfig = Object.assign(defaultConfig, this.config.editRules);
        console.log(defaultConfig)
      }
      return defaultConfig;
    },
    columns () {
      return this.config && this.config.columns ? this.config.columns : [];
    },
    // 计算所有列
    columnsCom () {
      const editable = this.editable;
      const isNewRecord = this.isNewRecord;
      const isCopy = this.isCopy;
      const form = this.form;
      let columns = this.columns;
      let data = [];
      if (columns) {
        for( let i in columns) {
          let column = columns[i];
          // 过滤不需要的列
          let filter = true;
          if (column.visibleFunction && typeof column.visibleFunction === 'function') {
            filter = column.visibleFunction({form, isCopy, isNewRecord, editable});
          }
          if (!filter) {
            continue;
          }
          // 配置宽度
          // if (column.width === undefined) {
          //   if (this.editable) {
          //     column.width = column.editWidth || '120';
          //   } else {
          //     column.width = column.viewWidth || '100';
          //   }
          // }
          // 列附加额外class
          let className = column.className;
          if (column.classNameFunction && typeof column.classNameFunction === 'function') {
            className = column.classNameFunction({form, editable});
          }
          column.className = className;
          // editRender
          let editRender = column.editRender;
          if (column.editRenderFunction && typeof column.editRenderFunction === 'function') {
            editRender = column.editRenderFunction({form, editable});
          }
          column.editRender = editRender;
          //cellRender
          let cellRender = column.cellRender;
          if (column.cellRenderFunction && typeof column.cellRenderFunction === 'function') {
            cellRender = column.cellRenderFunction({form, editable});
          }
          column.cellRender = cellRender;
          data.push(column);
        }
      }
      return data;
    },
    paramsCom () {
      let dataSource = this.dataSource || {};
      if (this.detailTableDataSource) {
        dataSource = Object.assign(dataSource, this.detailTableDataSource);
      }
      return {dataSource, table: this.$refs.erpTable ? this.$refs.erpTable.$refs.erpTable : null, form: this.form, editable: this.editable, isNewRecord: this.isNewRecord, isCopy: this.isCopy};
    },
    editConfigCom () {
      if (!this.editable) {
        return null;
      }
      let defaultConfig = null;
      if(this.editDetail) {
        defaultConfig = {trigger: 'manual', mode: 'row', showStatus: true, activeMethod: this.handleActiveMethod, showAsterisk: this.editable, showIcon: this.editable};
      } else {
        defaultConfig = {trigger: 'click', mode: 'cell', showStatus: true, activeMethod: this.handleActiveMethod, showAsterisk: this.editable, showIcon: this.editable};
      }
      if (this.config && this.config.editConfig && this.config.editConfig.activeMethod) {
        defaultConfig.activeMethod = (e) => {
          return this.config.editConfig.activeMethod(e, {form: this.form, editable: this.editable});
        };
      }
      let obj = Object.assign(defaultConfig, this.editConfig);
      return obj;
    },
    customConfigCom () {
      let defaultConfig = {storage: false};
      return Object.assign(defaultConfig, this.customConfig);
    },
    keyboardConfigCom () {
      let defaultConfig = {isArrow: true, isDel: true, isEnter: true, isTab: true, isEdit: true, editMethod: this.editMethod,enterToTab: true};
      return Object.assign(defaultConfig, this.keyboardConfig);
    },
    mouseConfigCom () {
      let defaultConfig = {selected: true};
      return Object.assign(defaultConfig, this.mouseConfig);
    },

    defaultData () {
      let count = 5;
      let data = [];
      for (let i = 0; i < count; i ++) {
        data.push({});
      }
      return this.isNewRecord ? data : this.data;
    }
  },
  watch: {
    "detailTableDataSource" : {
      handler(e) {
        this.$emit('change-data-source', {data: e});
      }
    },
    visible: {
      handler (visible, oldVisible) {
        if (visible && oldVisible !== visible) {
          this.getDataSource();
        }
      },
      immediate: true
    },
    'form.rate'() {
      this.updateFooter();
    },
    'form.sourceType' () {
      this.$emit('clear');
    },
    'form.type' () {
      this.$emit('clear');
    }
  },
  mounted() {
    if (this.draggable) {
      this.rowDrop();
    };
  },
  beforeDestroy() {
    if (this.createNewRecordTimer) {
      clearInterval(this.createNewRecordTimer);
    }
    if (this.sortable1) {
      this.sortable1.destroy();
    }
  },
  methods: {
    /**
     * 【已废弃】
     * @private
     */
    handleClear () {
      /**
       * 通知父组件表格已清空，【已废弃】
       */
      this.$emit('clear');
    },
    /**
     * 手动更新表格底部，用于更新表格计算总数或平均值
     * @private
     */
    updateFooter () {
      this.$refs.erpTable && this.$refs.erpTable.$refs.erpTable.updateFooter();
    },
    /**
     * 获取编辑表格表单的数据源
     * @private
     */
    getDataSource () {

      let url = this.apiList && this.apiList.dataSourceApi && this.apiList.dataSourceApi.url ? this.apiList.dataSourceApi.url : '';
      let query = this.apiList && this.apiList.dataSourceApi && this.apiList.dataSourceApi.query ? this.apiList.dataSourceApi.query : {};
      if (url) {
        request.post(url, query)
          .then(res => {
            let detailTableDataSource = {};
            let data = res.data.initDataItems;
            if (data) {
              data.map((item) => {
                detailTableDataSource[item.name] = item.items;
              });
            }
            this.detailTableDataSource = detailTableDataSource;
            this.registerComponents();
          })
          .catch(() => {
            this.detailTableDataSource = {};
          });
      } else {
        this.registerComponents();
      }
    },
    /**
     * 防止某些弹出组件在点击时，已激活单元格会变为未激活状态
     * @private
     */
    registerComponents() {
      VXETable.interceptor.add('event.clearActived', (params, event) => {
        // 比如点击了某个组件的弹出层面板之后，此时被激活单元格不应该被自动关闭，通过返回 false 可以阻止默认的行为。
        if (event.target.className.indexOf('vxe-modal--wrapper') > -1) {
          return false;
        }
      });
      if (this.isNewRecord) {
        // this.createNewRecordTimer = setInterval(() => {
        //     if (this.$refs.erpTable && this.$refs.erpTable.$refs.erpTable) {
        //         this.resetInsertData()
        //         clearInterval(this.createNewRecordTimer)
        //     }
        // }, 100)
      }
    },
    /**
     * 设置单元格是否可激活
     * @private
     * @returns {boolean}
     */
    handleActiveMethod () {
      return this.editable;
    },
    /**
     * 监听鼠标进入单元格
     * @private
     * @param $rowIndex
     */
    handleCellMouseenter ({$rowIndex}) {
      if (this.editable) {
        this.currentEnterRow = $rowIndex;
      }
    },
    /**
     * 监听鼠标离开
     * @private
     */
    handleCellMouseleave () {
      if (this.editable) {
        this.currentEnterRow = null;
      }
    },
    /**
     * 在表尾插入新行
     * @public
     * @param row
     * @returns {Promise<void>}
     */
    async insertTable(row) {
      await this.$refs.erpTable.$refs.erpTable.insertAt({}, -1);
    },
    /**
     * 删除传入的行
     * @public
     * @param {object} row 表格中的行
     * @returns {boolean}
     */
    deleteTable (row) {
      let list = this.$refs.erpTable.$refs.erpTable.getTableData().tableData;
      if (list && list.length === 1) {
        toast({
          message: '至少保留一条数据',
          type: 'warning'
        });
        return false;
      }
      this.$refs.erpTable.$refs.erpTable.remove([row]);
    },
    /**
     * 获取表格的所有数据
     * @public
     * @returns {{footerData: *, fullData: *, tableData: *, visibleData: *}|{footerData, fullData: *, tableData, visibleData}|{fullData: RowInfo[]; visibleData: RowInfo[]; tableData: RowInfo[]; footerData: any[][]}|{footerData: *, fullData: *, tableData: *, visibleData: *}|{footerData: *, fullData: *, tableData: *, visibleData: *}}
     */
    getTableData () {
      return this.$refs.erpTable.$refs.erpTable.getTableData();
    },
    /**
     * 只对 isEdit=true 有效，用于重写编辑单元格方法
     * @public
     * @param row
     * @param column
     * @returns {boolean}
     */
    editMethod ({ row, column }) {
      this.$refs.erpTable.$refs.erpTable.setActiveCell(row, column.property);
      return false;
    },
    /**
     * 表格全量验证
     * @public
     * @returns {Promise<T>}
     */
    async fullValidate () {
      return await this.$refs.erpTable.$refs.erpTable.fullValidate().catch(errMap => errMap);
    },
    /**
     * 验证表格某些行
     * @public
     * @param {object|array} rows 表格多行或单行数据
     * @returns {Promise<*>}
     */
    async validate (rows) {
      return await this.$refs.erpTable.$refs.erpTable.validate(rows).catch(errMap => errMap);
    },
    /**
     * 往表格插入临时数据（不支持深层结构），从指定位置插入一行或多行；第二个参数：row 指定位置（不支持树表格）、null从第一行插入、-1 从最后插入
     * @public
     * @param records
     * @param row
     * @returns {Promise<unknown>}
     */
    insertAt (records, row) {
      return this.$refs.erpTable.$refs.erpTable.insertAt(records, row).catch(errMap => errMap);
    },
    /**
     * 根据 row 获取相对于 data 中的索引
     * @public
     * @param row
     * @returns {number}
     */
    getRowIndex (row) {
      return this.$refs.erpTable.$refs.erpTable.getRowIndex(row);
    },
    /**
     * 获取数据，和 data 的行为一致，也可以指定索引获取数据
     * @public
     * @param rowIndex
     * @returns {*}
     */
    getData (rowIndex) {
      return this.$refs.erpTable.$refs.erpTable.getData(rowIndex);
    },
    /**
     * 创建 Row|Rows 对象（对于某些特殊场景需要对数据进行手动插入时可能会用到）
     * @public
     * @param records
     * @returns {Promise<any>}
     */
    createRow (records) {
      return this.$refs.erpTable.$refs.erpTable.createRow(records);
    },
    /**
     * 根据 row 获取相对于当前数据中的索引
     * @public
     * @param records
     * @returns {number}
     */
    getVMRowIndex (records) {
      return this.$refs.erpTable.$refs.erpTable.getVMRowIndex(records);
    },
    /**
     * 根据行获取行的唯一主键
     * @public
     * @param row
     * @returns {null|string}
     */
    getRowid (row) {
      return this.$refs.erpTable.$refs.erpTable.getRowid(row);
    },
    /**
     * 获取表格有效数据，过滤未编辑过的数据
     * @public
     * @returns {[]}
     */
    getEffectTableData () {
      //获取有效数据，过滤未编辑过的数据
      let originData = this.getTableData() ? this.getTableData().tableData : [];
      let effectData = [];
      const effectRow = this.effectRow;
      const hasEffectRow = effectRow && effectRow.length > 0;
      for (let i in originData) {
        let filter = true;
        // 若有传effectRow数组，则需要数组中每个字段的值都不能为空，否则需要判断除_XID外的所有字段是否为空，所有字段都为空表示该条为无效数据，否则表示有效数据
        if (hasEffectRow) {
          for (let rowIndex in effectRow) {
            if (originData[i][effectRow[rowIndex]] !== undefined && originData[i][effectRow[rowIndex]] !== null && originData[i][effectRow[rowIndex]] !== '') {
              filter = false;
              break;
            }
          }
        } else {
          for (let j in originData[i]) {
            if (originData[i][j] !== null && originData[i][j] !== '' && j !== '_XID') {
              filter = false;
              break;
            }
          }
        }
        if (!filter) {
          effectData.push(originData[i]);
        }
      }
      return effectData;
    },
    /**
     * 验证详情
     * @private
     * @returns {Promise<boolean>}
     */
    async validateDetail () {
      const errMap = await this.validate(this.getEffectTableData()).catch(errMap => errMap);
      if (errMap) {
        let msgList = [];
        Object.values(errMap).forEach(errList => {
          errList.forEach(params => {
            let { rowIndex, column, rules } = params;
            rules.forEach(rule => {
              msgList.push(`${column.title} 校验错误：${rule.message}`);
            });
          });
        });
        let html = '';
        if (msgList && msgList.length > 0) {
          for (let i in msgList) {
            html += '<div>' + msgList[i] + '</div>';
            break;
          }
        }
        toast({
          dangerouslyUseHTMLString: true,
          message: html,
          type: "error"
        });
        return false;
      }
      return true;
    },
    /**
     * 重置插入的数据，表格在刚加载时，默认会向插入多行(根据表格高度定)空数据。
     * @private
     * @param len
     */
    resetInsertData (len) {
      if (len === undefined) {
        len = 5;
      }
      if(len < 1) {
        len = 1;
      }
      let data = [];
      for (let i = 0; i < len; i ++) {
        data.push({});
      }
      this.$refs.erpTable.$refs.erpTable.loadData([]);
      this.$refs.erpTable.$refs.erpTable.insert(data);
    },
    /**
     * @private
     * 拖拽表格配置
     */
    rowDrop () {
      this.$nextTick(() => {
        let timer = setInterval(() => {
          if (this.$refs.erpTable && this.$refs.erpTable.$refs.erpTable) {
            const xTable = this.$refs.erpTable.$refs.erpTable;
            this.sortable1 = Sortable.create(xTable.$el.querySelector('.body--wrapper>.vxe-table--body tbody'), {
              handle: '.drag-btn',
              onEnd: ({ newIndex, oldIndex }) => {
                const {tableData} = xTable.getTableData();
                if (this.afterDrag) {
                  this.afterDrag({tableData,  table: xTable, newIndex, oldIndex});
                } else {
                  const currRow = tableData.splice(oldIndex, 1)[0];
                  tableData.splice(newIndex, 0, currRow);
                  xTable.loadData(tableData);
                }
              }
            });
            clearInterval(timer);
          }

        }, 100);

      });
    },

    handleManual(row) {
      console.log(row)
      this.$bus.$emit("columnClick", row)
    },

    handleEdit(row) {
      this.$bus.$emit("rowEditDetail", row)
    },

    handleSingleSelect(row) {
      this.$bus.$emit("columnSingleSelect", row)
    }
  }
};
</script>

<style lang="scss" scoped>
    $primaryColor: var(--primary-color);
    $primaryColor30: var(--primary-color30);
    $dangerColor: var(--danger-color);
    .seq-icons{
        width: 100%;
        display: flex;
        flex-wrap: nowrap;
        .seq-icon{
            flex:1;
            >i{
                text-align: center;
                cursor: pointer;
            }
            .add{
                color: $primaryColor;
            }
            .remove{
                color: $dangerColor;
            }
        }
    }
    ::v-deep{
        .erp-table-footer-row{
            background-color: $primaryColor30 !important;
        }

    }

</style>
